﻿// Type: System.Data.Objects.Internal.ObjectQueryState
// Assembly: System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.Entity.dll

using System;
using System.Data;
using System.Data.Metadata.Edm;
using System.Data.Objects;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime;
using System.Runtime.CompilerServices;

namespace System.Data.Objects.Internal
{
  internal abstract class ObjectQueryState
  {
    internal static readonly MergeOption DefaultMergeOption;
    private readonly ObjectContext _context;
    private readonly Type _elementType;
    private ObjectParameterCollection _parameters;
    private Span _span;
    private MergeOption? _userMergeOption;
    private bool _cachingEnabled;
    protected ObjectQueryExecutionPlan _cachedPlan;

    internal Type ElementType
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this._elementType;
      }
    }

    internal ObjectContext ObjectContext
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this._context;
      }
    }

    internal ObjectParameterCollection Parameters
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this._parameters;
      }
    }

    internal Span Span
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this._span;
      }
    }

    internal MergeOption EffectiveMergeOption
    {
      get
      {
        if (this._userMergeOption.HasValue)
          return this._userMergeOption.Value;
        ObjectQueryExecutionPlan queryExecutionPlan = this._cachedPlan;
        if (queryExecutionPlan != null)
          return queryExecutionPlan.MergeOption;
        else
          return ObjectQueryState.DefaultMergeOption;
      }
    }

    internal MergeOption? UserSpecifiedMergeOption
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this._userMergeOption;
      }
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set
      {
        this._userMergeOption = value;
      }
    }

    internal bool PlanCachingEnabled
    {
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] get
      {
        return this._cachingEnabled;
      }
      [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set
      {
        this._cachingEnabled = value;
      }
    }

    internal TypeUsage ResultType
    {
      get
      {
        ObjectQueryExecutionPlan queryExecutionPlan = this._cachedPlan;
        if (queryExecutionPlan != null)
          return queryExecutionPlan.ResultType;
        else
          return this.GetResultType();
      }
    }

    static ObjectQueryState()
    {
    }

    protected ObjectQueryState(Type elementType, ObjectContext context, ObjectParameterCollection parameters, Span span)
    {
      EntityUtil.CheckArgumentNull<Type>(elementType, "elementType");
      EntityUtil.CheckArgumentNull<ObjectContext>(context, "context");
      this._elementType = elementType;
      this._context = context;
      this._span = span;
      this._parameters = parameters;
    }

    internal ObjectParameterCollection EnsureParameters()
    {
      if (this._parameters == null)
      {
        this._parameters = new ObjectParameterCollection(this.ObjectContext.Perspective);
        if (this._cachedPlan != null)
          this._parameters.SetReadOnly(true);
      }
      return this._parameters;
    }

    internal void ApplySettingsTo(ObjectQueryState other)
    {
      other.PlanCachingEnabled = this.PlanCachingEnabled;
      other.UserSpecifiedMergeOption = this.UserSpecifiedMergeOption;
    }

    internal abstract bool TryGetCommandText(out string commandText);

    internal abstract bool TryGetExpression(out Expression expression);

    internal abstract ObjectQueryExecutionPlan GetExecutionPlan(MergeOption? forMergeOption);

    internal abstract ObjectQueryState Include<TElementType>(ObjectQuery<TElementType> sourceQuery, string includePath);

    protected abstract TypeUsage GetResultType();

    protected static MergeOption EnsureMergeOption(params MergeOption?[] preferredMergeOptions)
    {
      foreach (MergeOption? nullable in preferredMergeOptions)
      {
        if (nullable.HasValue)
          return nullable.Value;
      }
      return ObjectQueryState.DefaultMergeOption;
    }

    protected static MergeOption? GetMergeOption(params MergeOption?[] preferredMergeOptions)
    {
      foreach (MergeOption? nullable in preferredMergeOptions)
      {
        if (nullable.HasValue)
          return new MergeOption?(nullable.Value);
      }
      return new MergeOption?();
    }

    [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
    internal ObjectQuery CreateQuery()
    {
      return (ObjectQuery) typeof (ObjectQueryState).GetMethod("CreateObjectQuery", BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(new Type[1]
      {
        this._elementType
      }).Invoke((object) null, new object[1]
      {
        (object) this
      });
    }

    public static ObjectQuery<TResultType> CreateObjectQuery<TResultType>(ObjectQueryState queryState)
    {
      return new ObjectQuery<TResultType>(queryState);
    }
  }
}
